#include "pdiusb.h"
#include "uart.h"
#include "descriptor.h"
#include "keypad.h"

case_func idata interruptCase[8];
case_func_pU8 idata requestCase[3];
case_func_pU8 idata standarRequestCase[11];
case_func_pU8 idata standarDescriptorRequestCase[6];
case_desc idata standarStringDescCase[4];
DataPkg idata sendDataPkg;
u8 idata EndpointBuffer[16] = {0};
u8 idata hasSendHIDdesc = 0;

static u8 idata Ep1InIsBusy = 0;

static u8 D12ReadEndpointLastStatus(u8 endp);
static u8 D12ReadEndpointBuffer(u8 endp, u8 len, u8 *buf);
static void D12AcknowledgeSetup(void);
static void D12ClearBuffer(void);
static void D12SelectEndpoint(u8 endp);
static void UsbEp0SendData(DataPkg *dataPkg);
static void D12SetAddress(u8 address);
static void adjustSendDesc(u8 *buffer, u8 *desc);
static void D12SetEndpointEnable(u8 enable);

static DataPkg* setDataPkg(u8 len, u8 *pData)
{
	sendDataPkg.SendLength = len;
	sendDataPkg.pData = pData;
	sendDataPkg.NeedZeroPkg = 0;
	if(0 == len){
		sendDataPkg.NeedZeroPkg = 1;
	}

	return &sendDataPkg;
}

static void interruptCaseInit(void)
{
	interruptCase[0].case_num = 0x80;
	interruptCase[0].func     = UsbBusSuspend;

	interruptCase[1].case_num = 0x40;
	interruptCase[1].func     = UsbBusReset;

	interruptCase[2].case_num = 0x01;
	interruptCase[2].func     = UsbEp0Out;

	interruptCase[3].case_num = 0x02;
	interruptCase[3].func     = UsbEp0In;

	interruptCase[4].case_num = 0x04;
	interruptCase[4].func     = UsbEp1Out;

	interruptCase[5].case_num = 0x08;
	interruptCase[5].func     = UsbEp1In;

	interruptCase[6].case_num = 0x10;
	interruptCase[6].func     = UsbEp2Out;

	interruptCase[7].case_num = 0x20;
	interruptCase[7].func     = UsbEp2In;
}

static int StandarRequest(u8 *buffer)
{
    u8 i = 0;
    u8 array_len = 0;

    pr_dbg("standar request.\n");

    array_len = sizeof(standarRequestCase)/sizeof(standarRequestCase[0]);
    for(i=0; i<array_len; i++){
        if(standarRequestCase[i].case_num == buffer[1]){
            standarRequestCase[i].func(buffer);
            break;
        }
    }

    return 0;
}

static int ClassRequest(u8 *buffer)
{
	pr_dbg("class request.\n");

	buffer = buffer;

	return 0;
}

static int OEMRequest(u8 *buffer)
{
	pr_dbg("OEM request.\n");

	buffer = buffer;
	return 0;
}

static int RequestGetStatus(u8 *buffer)
{
	pr_dbg("Request get status.\n");

	buffer = buffer;
	return 0;
}

static int RequestClearFeature(u8 *buffer)
{
	pr_dbg("Request clear feature.\n");

	buffer = buffer;
	return 0;
}

static int RequestSetFeature(u8 *buffer)
{
	pr_dbg("Request set feature.\n");

	buffer = buffer;
	return 0;
}

static int RequestSetAddress(u8 *buffer)
{
	pr_dbg("Request set address.\n");

	/* only bit0~bit6 is addr */
	D12SetAddress(buffer[2]);
	pr_dbg("\nget addr is:");
	pr_hex_dbg(buffer[2]);
	pr_dbg("\n");
	/* send len==0 pkg */
	UsbEp0SendData(setDataPkg(0, (u8*)0));

	return 0;
}

/* get device descriptor */
static int RequestGetDescriptor(u8 *buffer)
{
	u8 i = 0;
	u8 array_len = 0;

	pr_dbg("Request get descriptor.\n");
	array_len = sizeof(standarDescriptorRequestCase)/sizeof(standarDescriptorRequestCase[0]);

	for(i=0; i<array_len; i++){
		if(buffer[3] == standarDescriptorRequestCase[i].case_num){
			standarDescriptorRequestCase[i].func(buffer);
			break;
		}
	}
	
	return 0;
}

/* set device descriptor */
static int RequestSetDescriptor(u8 *buffer)
{
	pr_dbg("Request set descriptor.\n");

	buffer = buffer;
	return 0;
}

static int RequestGetConfiguration(u8 *buffer)
{
	pr_dbg("Request get configuration.\n");

	buffer = buffer;
	return 0;
}

static int RequestSetConfiguration(u8 *buffer)
{
	pr_dbg("Request set configuration.\n");

	D12SetEndpointEnable(buffer[2]);
	UsbEp0SendData(setDataPkg(0, (u8*)0));
	return 0;
}

static int RequestGetInterface(u8 *buffer)
{
	pr_dbg("Request get interface.\n");

	buffer = buffer;
	return 0;
}

static int RequestSetInterface(u8 *buffer)
{
	pr_dbg("Request set interface.\n");

	buffer = buffer;
	return 0;
}

static int RequestSyncFrame(u8 *buffer)
{
	pr_dbg("Request sync frame.\n");

	buffer = buffer;
	return 0;
}

static void adjustSendDesc(u8 *buffer, u8 *desc)
{
	u8 requestLen = buffer[6];

	/* if host want more then the size of descriptor */
	if(requestLen>desc[0]){
		requestLen = desc[0];
	}

	UsbEp0SendData(setDataPkg(requestLen, desc));
}

static int RequestDeviceDescriptor(u8 *buffer)
{
	pr_dbg("Request Device Descriptor.\n");

	adjustSendDesc(buffer, DeviceDescriptor);

	return 0;
}

static int RequestConfigurationDescriptor(u8 *buffer)
{
	u8 requestLen = buffer[6];
	u8 descLen    = ConfigurationDescriptor[2];

	pr_dbg("Request Configuration Descriptor.\n");
	if(requestLen > descLen){
		requestLen = descLen;
	}
	
	UsbEp0SendData(setDataPkg(requestLen, ConfigurationDescriptor));
	return 0;
}

static int RequestStringDescriptor(u8 *buffer)
{
	u8 i = 0;
	u8 array_len = 0;

	pr_dbg("Request String Descriptor.\n");

	array_len = sizeof(standarStringDescCase)/sizeof(standarStringDescCase[0]);
	for(i=0; i<array_len; i++){
		if(buffer[2] == standarStringDescCase[i].case_num){
			adjustSendDesc(buffer, standarStringDescCase[i].desc);
			goto func_exit;
		}
	}

	/* if can not adjust string_ID, send 0 pkg */
	UsbEp0SendData(setDataPkg(0, (u8*)0));

func_exit:
	return 0;
}
static int RequestInterfaceDescriptor(u8 *buffer)
{
	pr_dbg("Request Interface Descriptor.\n");
	buffer = buffer;
	return 0;
}
static int RequestEndpointDescriptor(u8 *buffer)
{
	pr_dbg("Request Endpoint Descriptor.\n");

	buffer = buffer;
	return 0;
}

static int RequestHIDReportDescriptor(u8 *buffer)
{
	u8 requestLen = buffer[6];
	u8 array_len  = 0;

	pr_dbg("Request HID Report Descriptor.\n");

	array_len = sizeof(ReportDescriptor)/sizeof(ReportDescriptor[0]);
	/* if host want more then the size of descriptor */
	if(requestLen>array_len){
		requestLen = array_len;
	}

	UsbEp0SendData(setDataPkg(requestLen, ReportDescriptor));
	hasSendHIDdesc = 1;
	return 0;
}

int UsbBusSuspend(void)
{
	pr_dbg("Usb bus suspend.\n");
	return 0;
}

int UsbBusReset(void)
{
	pr_dbg("Usb bus reset.\n");
	Ep1InIsBusy = 0;
	return 0;
}

int UsbEp0Out(void)
{
    u8 *Buffer = EndpointBuffer;
    u8 i = 0;
    u8 array_len = 0;
    pr_dbg("Usb Ep0 Out.\n");

    if(D12ReadEndpointLastStatus(0) & 0x20){
    	/* this is setup pkg */
         D12ReadEndpointBuffer(0, 16, Buffer);
	 D12AcknowledgeSetup();
	 D12ClearBuffer();
         array_len = sizeof(requestCase)/sizeof(requestCase[0]);
         for(i=0; i<array_len; i++){
            /* adjust RequestType */
            if(requestCase[i].case_num == ((Buffer[0]>>5)&0x3)){
                /* adjust Request */
                requestCase[i].func(Buffer);
                break;
            }
         }
    }else {
    	/* not setup pkg */
	D12ReadEndpointBuffer(0, 16, Buffer);
	D12ClearBuffer();
    }

    return 0;
}

int UsbEp0In(void)
{
	pr_dbg("Usb Ep0 In.\n");

	/* read Endp0_IN status, to clear endp0 interrupt mark */
	D12ReadEndpointLastStatus(1);
	UsbEp0SendData(&sendDataPkg);

	return 0;
}

int UsbEp1Out(void)
{
	pr_dbg("Usb Ep1 Out.\n");
	return 0;
}

int UsbEp1In(void)
{
	pr_dbg("Usb Ep1 In.\n");
	D12ReadEndpointLastStatus(3);
	Ep1InIsBusy = 0;
	return 0;
}

int UsbEp2Out(void)
{
	pr_dbg("Usb Ep2 Out.\n");
	return 0;
}

int UsbEp2In(void)
{
	pr_dbg("Usb Ep2 In.\n");
	return 0;
}

void D12WriteCommand(u8 Command)
{
    D12SetCommandAddr(); 
    D12ClrWr();
    D12SetPortOut();
    D12SetData(Command);
    D12SetWr();
    D12SetPortIn();
}

u8 D12ReadByte(void)
{
    u8 tmp;
    D12SetDataAddr();
    D12ClrRd();
    tmp = D12GetData();
    D12SetRd();
    return tmp;
}

u16 D12ReadID(void)
{
    u16 id;
    D12WriteCommand(Read_ID);
    id = D12ReadByte();
    id |= ((u16)D12ReadByte())<<8;

    return id;
}

void D12WriteByte(u8 u8data)
{
    D12SetDataAddr();
    D12ClrWr();
    D12SetPortOut();
    D12SetData(u8data);
    D12SetWr();
    D12SetPortIn();
}

static void DelayXms(u16 x)
{
	  u16 i;
	  u16 j;
	  for(i=0;i<x;i++)
			  for(j=0;j<227;j++);
}

void UsbDisconnect(void)
{
	pr_dbg("usb disconnect.\n");
	D12WriteCommand(D12_SET_MODE);
	D12WriteByte(0x06);  /* disconnect the R, to tell host disconnect */
	D12WriteByte(0x47);
	DelayXms(1000);  /* delay 1s. */
}

void UsbConnect(void)
{
	pr_dbg("usb connect.\n");
	D12WriteCommand(D12_SET_MODE);
	D12WriteByte(0x16);  /* connect the R, to tell host connect */
	D12WriteByte(0x47);
}

static u8 D12ReadEndpointLastStatus(u8 endp)
{
	D12SelectEndpoint(endp);

	D12WriteCommand(0x40+endp);

	return D12ReadByte();
}

static void D12SelectEndpoint(u8 endp)
{
	D12WriteCommand(0x00+endp);
}

static u8 D12ReadEndpointBuffer(u8 endp, u8 len, u8 *buf)
{
	u8 i=0,j=0;
	
	D12SelectEndpoint(endp);
	D12WriteCommand(D12_READ_BUFFER);
	D12ReadByte();
	j = D12ReadByte();
	if(j>len){
		j = len;
	}
	pr_dbg("read Endpoint:");
	pr_hex_dbg(endp/2);
	pr_dbg("\n");

	pr_dbg("read buffer:");
	for(i=0; i<j; i++){
		D12ClrRd();
		*(buf+i) = D12GetData();
		D12SetRd();

		pr_hex_dbg(*(buf+i));
		pr_dbg(" ");
	}
	pr_dbg("\n");

	return j;
}

static void D12ClearBuffer(void)
{
	D12WriteCommand(D12_CLEAR_BUFFER);
}

static void D12AcknowledgeSetup(void)
{
	D12SelectEndpoint(1); /* Endp0 IN */
	D12WriteCommand(D12_ACKNOWLEDGE_SETUP);
	D12SelectEndpoint(0); /* Endp0 OUT */
	D12WriteCommand(D12_ACKNOWLEDGE_SETUP);
}

static void D12ValidateBuffer(void)
{
	D12WriteCommand(D12_VALIDATA_BUFFER);
}

static u8 D12WriteEndpointBuffer(u8 endp, u8 len, u8 *buf)
{
	u8 i = 0;

	D12SelectEndpoint(endp);
	D12WriteCommand(D12_WRITE_BUFFER);
	D12WriteByte(0);
	D12WriteByte(len);

	pr_dbg("\nwrite endpoint:");
	pr_hex_dbg(endp/2);
	pr_dbg("\n");

	D12SetPortOut();

	if(buf != (u8*)0){
		for(i=0; i<len; i++){
			D12ClrWr();
			D12SetData(buf[i]);
			pr_hex_dbg(buf[i]);
			pr_dbg(" ");
			D12SetWr();
		}
	}
	pr_dbg("\n");

	D12SetPortIn();
	D12ValidateBuffer();

	return len;
}

static void D12SetAddress(u8 address)
{
	D12WriteCommand(D12_SET_ADDRESS_ENABLE);
	/* bit7: set enable, for next enable normal Endpoint.(not endp0) */
	D12WriteByte(0x80|address);
}

/* @enable: 1,enable; 0,disable */
static void D12SetEndpointEnable(u8 enable)
{
	D12WriteCommand(D12_SET_ENDPOINT_ENABLE);

	D12WriteByte(enable!=0?0x01:0x00);
}

static void UsbEp0SendData(DataPkg *dataPkg)
{
    u8 *SendLength = &(dataPkg->SendLength);
    u8 **ppSendData = &(dataPkg->pData);
    u8 *NeedZeroPkg = &(dataPkg->NeedZeroPkg);
    u8 endp0MaxPkgSize = DeviceDescriptor[7];

    /* the send_len is bigger then the max size of endpoint0 */
    if(*SendLength > endp0MaxPkgSize){
        D12WriteEndpointBuffer(1, endp0MaxPkgSize, *ppSendData);
	*ppSendData += endp0MaxPkgSize;
        *SendLength -= endp0MaxPkgSize;
    }
    else if(*SendLength > 0){
        D12WriteEndpointBuffer(1, *SendLength, *ppSendData);
	*ppSendData = (u8*)0;
	{if(*SendLength == endp0MaxPkgSize) *NeedZeroPkg = 1;}
        *SendLength = 0;
    }
    else if(*SendLength == 0 && *NeedZeroPkg == 1){
    	pr_dbg("\nsend 0 pkg.\n");
	*ppSendData = (u8*)0;
        D12WriteEndpointBuffer(1, 0, *ppSendData);
        *NeedZeroPkg = 0;
    }
    
}
 
void SendReport(void)
{
	u8 buffer[8] = {0};
	static u8 buffer3 = 0;

	if(0 == Ep1InIsBusy){

		if(1 == key1_pressd()){
			if(0x5b != buffer3){
				pr_dbg("in SendReport.\n");
				buffer[3] = 0x5b;
				buffer3 = 0x5b;
				D12WriteEndpointBuffer(3,sizeof(buffer)/sizeof(buffer[0]),buffer);
				Ep1InIsBusy = 1;
			}
		}else if(0 == key1_pressd()){
			if(0 != buffer3){
				pr_dbg("in SendReport.\n");
				buffer[3] = 0;
				buffer3 = 0;
				D12WriteEndpointBuffer(3,sizeof(buffer)/sizeof(buffer[0]),buffer);
				Ep1InIsBusy = 1;		
			}
		}


	}
}

static void standarStringDescCaseInit(void)
{
	standarStringDescCase[0].case_num = 0;
	standarStringDescCase[0].desc = LanguageId;

	standarStringDescCase[1].case_num = 1;
	standarStringDescCase[1].desc = ManufacturerStringDescriptor;

	standarStringDescCase[2].case_num = 2;
	standarStringDescCase[2].desc = ProductStringDescriptor;

	standarStringDescCase[3].case_num = 3;
	standarStringDescCase[3].desc = SerialNumberStringDescriptor;
}

static void standarRequestCaseInit(void)
{
	standarRequestCase[0].case_num = 0;
	standarRequestCase[0].func = RequestGetStatus;

	standarRequestCase[2].case_num = 1;
	standarRequestCase[2].func = RequestClearFeature;

	standarRequestCase[3].case_num = 3;
	standarRequestCase[3].func = RequestSetFeature;

	standarRequestCase[4].case_num = 5;
	standarRequestCase[4].func = RequestSetAddress;

	standarRequestCase[5].case_num = 6;
	standarRequestCase[5].func = RequestGetDescriptor;

	standarRequestCase[6].case_num = 7;
	standarRequestCase[6].func = RequestSetDescriptor;

	standarRequestCase[7].case_num = 8;
	standarRequestCase[7].func = RequestGetConfiguration;

	standarRequestCase[8].case_num = 9;
	standarRequestCase[8].func = RequestSetConfiguration;

	standarRequestCase[9].case_num = 10;
	standarRequestCase[9].func = RequestGetInterface;

	standarRequestCase[10].case_num = 11;
	standarRequestCase[10].func = RequestSetInterface;

	standarRequestCase[11].case_num = 12;
	standarRequestCase[11].func = RequestSyncFrame;
}

static void standarDescriptorRequestCaseInit(void)
{
	standarDescriptorRequestCase[0].case_num = 1;
	standarDescriptorRequestCase[0].func = RequestDeviceDescriptor;

	standarDescriptorRequestCase[1].case_num = 2;
	standarDescriptorRequestCase[1].func = RequestConfigurationDescriptor;

	standarDescriptorRequestCase[2].case_num = 3;
	standarDescriptorRequestCase[2].func = RequestStringDescriptor;

	standarDescriptorRequestCase[3].case_num = 4;
	standarDescriptorRequestCase[3].func = RequestInterfaceDescriptor;

	standarDescriptorRequestCase[4].case_num = 5;
	standarDescriptorRequestCase[4].func = RequestEndpointDescriptor;

	standarDescriptorRequestCase[5].case_num = 0x22;
	standarDescriptorRequestCase[5].func = RequestHIDReportDescriptor;
}

static void requestCaseInit(void)
{
	/* standar request */
	requestCase[0].case_num = 0;
	requestCase[0].func     = StandarRequest;

	/* class  */
	requestCase[1].case_num = 1;
	requestCase[1].func     = ClassRequest;

	/* OEM */
	requestCase[2].case_num = 2;
	requestCase[2].func     = OEMRequest;
}

void UsbInit(void)
{
	interruptCaseInit();
	requestCaseInit();
	standarRequestCaseInit();
	standarDescriptorRequestCaseInit();
	standarStringDescCaseInit();
}
